/**
 * 常见文件类型的 MIME 类型映射
 */
const MIME_TYPE_MAP: Record<string, string[]> = {
  // 图片
  '.jpg': ['image/jpeg', 'image/jpg'],
  '.jpeg': ['image/jpeg', 'image/jpg'],
  '.png': ['image/png'],
  '.gif': ['image/gif'],
  '.webp': ['image/webp'],
  '.svg': ['image/svg+xml'],
  '.bmp': ['image/bmp'],
  '.ico': ['image/x-icon', 'image/vnd.microsoft.icon'],

  // 音频
  '.mp3': ['audio/mpeg', 'audio/mp3'],
  '.wav': ['audio/wav', 'audio/wave'],
  '.ogg': ['audio/ogg'],
  '.m4a': ['audio/mp4'],

  // 视频
  '.mp4': ['video/mp4'],
  '.webm': ['video/webm'],
  '.avi': ['video/x-msvideo'],
  '.mov': ['video/quicktime'],

  // 文档
  '.pdf': ['application/pdf'],
  '.doc': ['application/msword'],
  '.docx': [
    'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  ],
  '.xls': ['application/vnd.ms-excel'],
  '.xlsx': ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
  '.ppt': ['application/vnd.ms-powerpoint'],
  '.pptx': [
    'application/vnd.openxmlformats-officedocument.presentationml.presentation',
  ],

  // 压缩文件
  '.zip': ['application/zip'],
  '.rar': ['application/x-rar-compressed'],
  '.7z': ['application/x-7z-compressed'],

  // 文本
  '.txt': ['text/plain'],
  '.csv': ['text/csv'],
  '.json': ['application/json'],
  '.xml': ['application/xml', 'text/xml'],
}

/**
 * 从MIME类型获取文件扩展名
 */
const getExtensionFromMimeType = (mimeType: string): string => {
  mimeType = mimeType.toLowerCase().split(';')[0].trim()

  for (const [ext, types] of Object.entries(MIME_TYPE_MAP)) {
    if (types.includes(mimeType)) {
      return ext
    }
  }

  // 如果找不到对应的扩展名，从 MIME 类型推测
  const genericType = mimeType.split('/')[0]
  switch (genericType) {
    case 'image':
      return '.png'
    case 'audio':
      return '.mp3'
    case 'video':
      return '.mp4'
    case 'text':
      return '.txt'
    default:
      return ''
  }
}

/**
 * 从URL获取文件名
 */
const getFileNameFromUrl = (url: string, contentType: string): string => {
  try {
    // 从 URL 中提取文件名
    const urlParts = url.split('/')
    let fileName = urlParts[urlParts.length - 1]

    // 移除URL参数
    fileName = fileName.split('?')[0]

    // 解码文件名
    fileName = decodeURIComponent(fileName)

    // 如果文件名为空或只包含扩展名，使用默认名称
    if (!fileName || fileName.startsWith('.')) {
      return `download${getExtensionFromMimeType(contentType)}`
    }

    // 检查是否已经有扩展名
    const hasExtension = fileName.includes('.')
    if (hasExtension) {
      return fileName // 如果URL中已有扩展名，直接使用
    }

    // 如果没有扩展名，添加对应的扩展名
    return `${fileName}${getExtensionFromMimeType(contentType)}`
  } catch (e) {
    console.warn('File name processing failed:', e)
    return `download${getExtensionFromMimeType(contentType)}`
  }
}

interface DownloadOptions {
  /** 自定义文件名 */
  fileName?: string
  /** 自定义请求头 */
  headers?: Record<string, string>
  /** 下载进度回调函数 */
  onProgress?: (progress: number) => void
  /** 是否自动添加正确的文件扩展名 */
  autoExtension?: boolean
}

/**
 * 通用文件下载函数
 */
export const downloadFile = async (
  url: string,
  options: DownloadOptions = {},
): Promise<void> => {
  const { fileName, headers = {}, onProgress, autoExtension = true } = options

  try {
    // 发起请求
    const response = await fetch(url, { headers })
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`)
    }

    // 获取文件大小
    const contentLength = Number(response.headers.get('content-length'))
    const contentType =
      response.headers.get('content-type') || 'application/octet-stream'

    // 如果支持进度回调，使用 ReadableStream
    if (onProgress && contentLength) {
      const reader = response.body!.getReader()
      const chunks: Uint8Array[] = []
      let receivedLength = 0

      while (true) {
        const { done, value } = await reader.read()
        if (done) break

        chunks.push(value)
        receivedLength += value.length
        onProgress(receivedLength / contentLength)
      }

      // 合并数据
      const blob = new Blob(chunks)
      triggerDownload(
        blob,
        fileName || getFileNameFromUrl(url, contentType),
        contentType,
        autoExtension,
      )
    } else {
      // 不需要进度回调时直接下载
      const blob = await response.blob()
      triggerDownload(
        blob,
        fileName || getFileNameFromUrl(url, contentType),
        contentType,
        autoExtension,
      )
    }
  } catch (error) {
    console.error('下载失败:', error)
    throw error
  }
}

/**
 * 触发文件下载
 */
const triggerDownload = (
  blob: Blob,
  fileName: string,
  contentType: string,
  autoExtension: boolean,
): void => {
  // 创建下载链接
  const downloadUrl = window.URL.createObjectURL(blob)
  const link = document.createElement('a')
  link.href = downloadUrl

  // 处理文件名和扩展名
  if (autoExtension) {
    const extension = getExtensionFromMimeType(contentType)
    if (extension && !fileName.toLowerCase().endsWith(extension)) {
      fileName = fileName.replace(/\.[^/.]+$/, '') + extension
    }
  }

  link.download = fileName

  // 触发下载
  document.body.appendChild(link)
  link.click()

  // 清理
  document.body.removeChild(link)
  window.URL.revokeObjectURL(downloadUrl)
}

/**
 * 批量下载文件
 */
export const downloadFiles = async (
  urls: string[],
  options: Omit<DownloadOptions, 'fileName'> = {},
): Promise<void> => {
  try {
    await Promise.all(urls.map((url) => downloadFile(url, options)))
  } catch (error) {
    console.error('批量下载失败:', error)
    throw error
  }
}
